#ifndef __MPI_TRACER_H
#define __MPI_TRACER_H
/*
 *  * MPI_Init_thread constants
 *   * Do not change the order of these without also modifying mpif.h.in.
 *    */
enum {
  MPI_THREAD_SINGLE,
  MPI_THREAD_FUNNELED,
  MPI_THREAD_SERIALIZED,
  MPI_THREAD_MULTIPLE
};

typedef struct{
    /* These fields are publicly defined in the MPI specification.
 *        User applications may freely read from these fields. */
    int MPI_SOURCE;
    int MPI_TAG;
    int MPI_ERROR;
    /* The following two fields are internal to the Open MPI
 *        implementation and should not be accessed by MPI applications.
 *               They are subject to change at any time.  These are not the
 *                      droids you're looking for. */
    int _cancelled;
    size_t _ucount;
}MPI_Status;

typedef void *MPI_Comm;
typedef void *MPI_Group;
typedef void *MPI_Request;
typedef void *MPI_Op;
typedef void *MPI_Datatype;
typedef void *MPI_Info;
int MPI_Get_count(const MPI_Status *status, MPI_Datatype datatype, int *count);
int MPI_Type_size(MPI_Datatype type, int *size);
int MPI_Gatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
                               void *recvbuf, const int recvcounts[], const int displs[],
                               MPI_Datatype recvtype, int root, MPI_Comm comm);
int MPI_Gather(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
                              void *recvbuf, int recvcount, MPI_Datatype recvtype,
                              int root, MPI_Comm comm);
int MPI_Barrier(MPI_Comm comm);
int MPI_Get_processor_name(char *name, int *resultlen);
int MPI_Comm_rank(MPI_Comm comm, int *rank);
int MPI_Group_translate_ranks(MPI_Group group1, int n, const int ranks1[],
                                             MPI_Group group2, int ranks2[]);
int MPI_Comm_group(MPI_Comm comm, MPI_Group *group);
int MPI_Comm_size(MPI_Comm comm, int *size);
// Intel MPI
#define MPI_COMM_NULL      ((MPI_Comm)0x04000000)
#define MPI_STATUS_IGNORE ((MPI_Status *) 0)
#define MPI_ANY_SOURCE -2

typedef int(*MPI_INIT)(int *argc, char ***argv);
typedef int(*MPI_INIT_THREAD)(int *argc, char ***argv,
    int required, int *provided);
typedef int(*MPI_FINALIZE)();

typedef int(*MPI_SEND)(const void *buf, int count, MPI_Datatype datatype, int dest,
    int tag, MPI_Comm comm);
typedef int(*MPI_ISEND)(const void *buf, int count, MPI_Datatype datatype, int dest,
    int tag, MPI_Comm comm, MPI_Request *request);
typedef int(*MPI_SSEND)(const void *buf, int count, MPI_Datatype datatype, int dest,
    int tag, MPI_Comm comm);
typedef int(*MPI_ISSEND)(const void *buf, int count, MPI_Datatype datatype, int dest,
    int tag, MPI_Comm comm, MPI_Request *request);
typedef int (*MPI_BSEND)(const void *buf, int count, MPI_Datatype datatype,
    int dest, int tag, MPI_Comm comm);
typedef int(*MPI_IBSEND)(const void *buf, int count, MPI_Datatype datatype, int dest,
    int tag, MPI_Comm comm, MPI_Request *request);
typedef int (*MPI_RSEND)(const void *buf, int count, MPI_Datatype datatype,
    int dest, int tag, MPI_Comm comm);
typedef int(*MPI_IRSEND)(const void *buf, int count, MPI_Datatype datatype, int dest,
    int tag, MPI_Comm comm, MPI_Request *request);
typedef int(*MPI_RECV)(void *buf, int count, MPI_Datatype datatype,
    int source, int tag, MPI_Comm comm, MPI_Status *status);
typedef int(*MPI_IRECV)(void *buf, int count, MPI_Datatype datatype,
        int source, int tag, MPI_Comm comm, MPI_Request *request);
typedef int (*MPI_RECV_INIT)(void *buf, int count, MPI_Datatype type, int source,
                  int tag, MPI_Comm comm, MPI_Request *request);
typedef int(*MPI_WAIT)(MPI_Request *request, MPI_Status *status);
typedef int(*MPI_WAITALL)(int count, MPI_Request array_of_requests[],
    MPI_Status *array_of_statuses);
typedef int (*MPI_WAITANY)(int count, MPI_Request requests[], int *indx, MPI_Status *status);
typedef int(*MPI_TEST)(MPI_Request *request, int *flag, MPI_Status *status);
typedef int(*MPI_TESTALL)(int count, MPI_Request array_of_requests[],
    int *flag, MPI_Status array_of_statuses[]);
typedef int(*MPI_ALLTOALL)(const void *sendbuf, int sendcount,
    MPI_Datatype sendtype, void *recvbuf, int recvcount,
    MPI_Datatype recvtype, MPI_Comm comm);
typedef int(*MPI_ALLTOALLV)(const void *sendbuf, const int sendcounts[],
                  const int sdispls[], MPI_Datatype sendtype,
                  void *recvbuf, const int recvcounts[], const int rdispls[],
                  MPI_Datatype recvtype, MPI_Comm comm);
typedef int(*MPI_BCAST)(void *buffer, int count, MPI_Datatype datatype,
    int root, MPI_Comm comm);
typedef int(*MPI_IBCAST)(void *buffer, int count, MPI_Datatype datatype,
    int root, MPI_Comm comm, MPI_Request *request);
typedef int(*MPI_REDUCE)(const void *sendbuf, void *recvbuf, int count,
               MPI_Datatype datatype, MPI_Op op, int root,
               MPI_Comm comm);
typedef int(*MPI_IREDUCE)(const void *sendbuf, void *recvbuf, int count,
                MPI_Datatype datatype, MPI_Op op, int root,
                MPI_Comm comm, MPI_Request *request);
typedef int(*MPI_ALLREDUCE)(const void *sendbuf, void *recvbuf, int count,
                  MPI_Datatype datatype, MPI_Op op, MPI_Comm comm);
typedef int(*MPI_IALLREDUCE)(const void *sendbuf, void *recvbuf, int count,
                   MPI_Datatype datatype, MPI_Op op, MPI_Comm comm,
                   MPI_Request *request);
typedef int(*MPI_IALLTOALL)(const void *sendbuf, int sendcount,
    MPI_Datatype sendtype, void *recvbuf, int recvcount,
    MPI_Datatype recvtype, MPI_Comm comm, MPI_Request *request);
typedef int (*MPI_IALLTOALLV)(const void *sendbuf, const int sendcounts[], const int sdispls[],
                   MPI_Datatype sendtype, void *recvbuf, const int recvcounts[],
                   const int rdispls[], MPI_Datatype recvtype, MPI_Comm comm,
                   MPI_Request *request);
typedef int (*MPI_INEIGHBOR_ALLTOALLV)(const void *sendbuf, const int sendcounts[], const int sdispls[],
                            MPI_Datatype sendtype, void *recvbuf, const int recvcounts[],
                            const int rdispls[], MPI_Datatype recvtype, MPI_Comm comm,
                            MPI_Request *request);
typedef int(*MPI_BARRIER)(MPI_Comm comm);
typedef int(*MPI_IBARRIER)(MPI_Comm comm, MPI_Request *request);

typedef int (*MPI_COMM_SPLIT)(MPI_Comm comm, int color, int key,
    MPI_Comm *newcomm);

typedef int (*MPI_COMM_SPLIT_TYPE)(MPI_Comm comm, int split_type, int key,
                    MPI_Info info, MPI_Comm *newcomm);
typedef int (*MPI_COMM_DUP)(MPI_Comm comm, MPI_Comm *newcomm);

typedef int (*MPI_COMM_CREATE)(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm);

typedef int (*MPI_CART_CREATE)(MPI_Comm old_comm, int ndims, const int dims[],
                    const int periods[], int reorder, MPI_Comm *comm_cart);

typedef int (*MPI_GRAPH_CREATE)(MPI_Comm old_comm, int nnodes, const int indx[],
                     const int edges[], int reorder, MPI_Comm *comm_graph);

typedef int (*MPI_DIST_GRAPH_CREATE_ADJACENT)(MPI_Comm comm_old,
                                   int indegree, const int sources[],
                                   const int sourceweights[], int outdegree,
                                   const int destinations[], const int destweights[],
                                   MPI_Info info, int reorder,
                                   MPI_Comm *comm_dist_graph);

typedef int (*MPI_INTERCOMM_CREATE)(MPI_Comm local_comm, int local_leader,
                         MPI_Comm bridge_comm, int remote_leader,
                         int tag, MPI_Comm *newintercomm);
typedef int (*MPI_INTERCOMM_MERGE)(MPI_Comm intercomm, int high,MPI_Comm *newcomm);

typedef int (*MPI_CART_SUB)(MPI_Comm comm, const int remain_dims[], MPI_Comm *new_comm);

typedef int(*MPI_GATHER)(const void *sendbuf, int sendcount,
    MPI_Datatype sendtype, void *recvbuf, int recvcount, 
    MPI_Datatype recvtype, int root, MPI_Comm comm);

typedef int (*MPI_GATHERV)(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
                void *recvbuf, const int recvcounts[], const int displs[],
                MPI_Datatype recvtype, int root, MPI_Comm comm);

typedef int(*MPI_IGATHER)(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
                void *recvbuf, int recvcount, MPI_Datatype recvtype,
                int root, MPI_Comm comm, MPI_Request *request);
typedef int (*MPI_IGATHERV)(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
                 void *recvbuf, const int recvcounts[], const int displs[],
                 MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request *request);

typedef int(*MPI_ALLGATHER)(const void *sendbuf, int sendcount, 
    MPI_Datatype sendtype, void *recvbuf, int recvcount, 
    MPI_Datatype recvtype, MPI_Comm comm);

typedef int (*MPI_ALLGATHERV)(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
                   void *recvbuf, const int recvcounts[],
                   const int displs[], MPI_Datatype recvtype, MPI_Comm comm);

typedef int(*MPI_IALLGATHER)(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
                   void *recvbuf, int recvcount, MPI_Datatype recvtype,
                   MPI_Comm comm,  MPI_Request *request);

typedef int (*MPI_IALLGATHERV)(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
                    void *recvbuf, const int recvcounts[], const int displs[],
                    MPI_Datatype recvtype, MPI_Comm comm, MPI_Request *request);

typedef int(*MPI_SCATTER)(const void *sendbuf, int sendcount, 
    MPI_Datatype sendtype, void *recvbuf, int recvcount, 
    MPI_Datatype recvtype, int root, MPI_Comm comm);

typedef int (*MPI_SCATTERV)(const void *sendbuf, const int sendcounts[], const int displs[],
                 MPI_Datatype sendtype, void *recvbuf, int recvcount,
                 MPI_Datatype recvtype, int root, MPI_Comm comm);

typedef int(*MPI_ISCATTER)(const void *sendbuf, int sendcount, 
    MPI_Datatype sendtype, void *recvbuf, int recvcount, 
    MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request *request);

typedef int (*MPI_ISCATTERV)(const void *sendbuf, const int sendcounts[], const int displs[],
                  MPI_Datatype sendtype, void *recvbuf, int recvcount,
                  MPI_Datatype recvtype, int root, MPI_Comm comm, MPI_Request *request);
typedef int (*MPI_SENDRECV)(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
                 int dest, int sendtag, void *recvbuf, int recvcount,
                 MPI_Datatype recvtype, int source, int recvtag,
                 MPI_Comm comm,  MPI_Status *status);
typedef int (*MPI_REDUCE_SCATTER)(const void *sendbuf, void *recvbuf, const int recvcounts[],
                       MPI_Datatype datatype, MPI_Op op, MPI_Comm comm);


#endif
